/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package br.ufrj.dcc.pushpeer.observers;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import br.ufrj.dcc.pushpeer.protocol.PushPeer;

import peersim.config.Configuration;
import peersim.core.CommonState;
import peersim.core.Control;
import peersim.core.Network;
import peersim.core.Node;

public class DownloadCompletionObserver implements Control {

	public DownloadCompletionObserver(String prefix) {
		pid = Configuration.getPid(prefix + "." + PAR_PROT);
		
		numFiles = Configuration.getInt(prefix + "." + NUM_FILES);
		
		executionTimes = Configuration.getInt(NUM_TIMES_EXECUTED);
		
		sumCompletionTimes = new HashMap<Integer, Long>();
		numPolledPeers = new HashMap<Integer, Integer>();
		
		for(int i=1; i <= numFiles; i++) {
			sumCompletionTimes.put(i, 0L);
			numPolledPeers.put(i, 0);
		}
		
		file = new File("graphs\\gnuplot_down_completion.dat");
		writer = null;
		try {
			writer = new FileWriter(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		try {
			writer.write("##avg_download_completion_time\r\n");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 *	The protocol to operate on.
	 */
	private static final String PAR_PROT="protocol";
	
	/**
	 * The number of files being simulated.
	 */
	private static final String NUM_FILES="num_files";
	
	/**
	 * The number of files being simulated.
	 */
	private static final String NUM_TIMES_EXECUTED="NUM_TIMES_DOWN_COMPLETION";
	
	/**
	 *	Protocol identifier, obtained from config property.
	 */
	private final int pid;
	
	/**
	 * Number of files being simulated.
	 */
	private int numFiles;
	
	/**
	 * Used for gnuplot output printing.
	 */
	private File file;
	
	/**
	 * Used for gnuplot output printing.
	 */
	private FileWriter writer;
	
	/**
	 * Holds the sum of the download completion times for every peer polled.
	 */
	private Map<Integer, Long> sumCompletionTimes;
	
	/**
	 * Holds the number of peers polled.
	 */
	private Map<Integer, Integer> numPolledPeers;
	
	/**
	 * Holds the number of times this observer has been executed.
	 */
	private int executionCount = 0;
	
	/**
	 * Holds the number of times this observer is to be executed.
	 */
	private int executionTimes;
	
	@Override
	public boolean execute() {
		executionCount++;
		
		if(executionCount < executionTimes/2) //Start the statistics only after half-time of simulation.
			return false;
		
		int numberOfNodes = Network.size();
		
		for(int j=0; j < numberOfNodes; j++) {
			Node n = Network.get(j);
			PushPeer p = (PushPeer)n.getProtocol(pid);
			
			if(p.getInitialTime() > CommonState.getEndTime()/2) {
				for(int i=1; i <= numFiles; i++) {
					if(p.getToBeCachedFile() != i) { //Do not consider the case where the file is a to-be-cached file. Will drag down the results.
						if(!p.alreadyPolled.get(i)) {
							if(p.downloadCompletionTime.get(i) != Long.MIN_VALUE) {
								sumCompletionTimes.put(i, sumCompletionTimes.get(i)+p.downloadCompletionTime.get(i));
								numPolledPeers.put(i, numPolledPeers.get(i)+1);
								p.alreadyPolled.put(i, true);
							}
						}
					}
				}
			}
		}
		
		if(executionCount == executionTimes) {
			for(int i=1; i <= numFiles; i++) {
				try {
					if(numPolledPeers.get(i) != 0) {
						writer.write(((double)sumCompletionTimes.get(i))/numPolledPeers.get(i) + "\r\n");
					}
					else {
						writer.write(0.0 + "\r\n");
					}
					writer.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		return false;
	}

}
